iT邦幫忙

2022 iThome 鐵人賽

DAY 26
0
Software Development

歡迎來到 GIS 的世界!30 天從後端開始學 GIS系列 第 26

旅遊規劃小專案 4 - 縣市找景點

  • 分享至 

  • xImage
  •  

文章同步發表至 Medium

縣市找景點的完整功能描述如下:

  • 身為一個使用者,我可以點擊地圖上的查詢按鈕,選擇縣市之後找到該縣市的景點。
  • 身為一個使用者,查詢縣市景點之後,地圖上只會呈現該縣市的景點。

從後端的角度來看,第一點是我們要做到的事情,所以首先,我們來檢視一下資料庫裡有沒有儲存到相關的縣市資訊:

這是我們在前幾天寫出來的 API,直接撈取資料庫的所有資料然後回傳——看起來除了 XY 座標和 address 之外,我們沒有任何和縣市有關的資訊。假設今天我們不只要做縣市,還需要細分到鄉鎮市區的時候,純文字、沒有固定格式的 address,要如何特別找到綠島鄉呢?

因此,我們要從資料庫裏面的 Geometry 著手,利用縣市的範圍找到交集,決定哪些景點在使用者選取的縣市內。

縣市界線

這個時候,政府資料開放平台就派上用場了。裡面由國土測繪中心所提供的直轄市、縣市界線是一個很好用的素材,可以讓我們藉由讀取檔案,找到縣市的 Geometry,接著再利用 NetTopologySuite 去針對我們資料庫裡的資料作處理。

在使用之前要注意:我們的資料所儲存的座標系統是 4326,國土測繪中心所提供的是 以 TWD97 為基準的 Shapefile,所以要先使用 QGIS Export Feature As 的功能,匯出成 4326 再繼續使用喔。

API

步驟很簡單,讀取縣市界線的 Shapefile,找到的話就和景點的清單做比較,如果景點在這個縣市裡(Within),就撈出來:

/// <summary> 縣市裡的景點清單 </summary>
/// <param name="county">縣市代碼</param>
[HttpGet("{county}")]
public IActionResult ScenicSpotInCounty(string county)
{
    // 建立一個空的 Geometry
    Geometry? countyGeometry = null;
    
    // 讀取 Shapefile
    foreach (var feature in Shapefile.ReadAllFeatures(@"C:\Users\user\Downloads\mapdata202209220943\COUNTY_MOI_1090820_4326.shp"))
    {
        // 如果 COUNTYID 的欄位等於傳入的縣市代碼則記錄下這筆 Geometry
        if (feature.Attributes["COUNTYID"].ToString() == county)
        {
            countyGeometry = feature.Geometry;
            break;
        }
    }
    
    // 處理找不到縣市代碼的情況
    if (countyGeometry == null) throw new KeyNotFoundException($"找不到代碼為 {county} 的縣市");
    
    var data = _db.ScenicSpots
        .Where(s => s.Geom.Within(countyGeometry))
        .Select(s => new ScenicSpotInfo()
        {
            Id = s.Id,
            Name = s.Name,
            Telephone = s.Telephone ?? "",
            Address = s.Address ?? "",
            X = s.Geom.Centroid.X,
            Y = s.Geom.Centroid.Y,
            Type = s.Type ?? "未分類",
            Park = s.Park ?? "",
            Info = s.Info ?? "暫無詳細資訊",
            UpdateTime = s.UpdateTime
        }).ToList();
    
    return Ok(data);
}

如果比較喜歡使用 Contains 的話,請記得把第 24 行修改一下喔:

.Where(s => countyGeometry.Contains(s.Geom))

Reference


上一篇
旅遊規劃小專案 3 - 網頁呈現
下一篇
旅遊規劃小專案 5 - 查詢介面
系列文
歡迎來到 GIS 的世界!30 天從後端開始學 GIS30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言